package function

import (
	crypto "crypto/rand"
	"errors"
	"github.com/gin-gonic/gin"
	. "go_tempate/SQL/table"
	. "go_tempate/common/store"
	. "go_tempate/common/struct"
	. "go_tempate/common/validator"
	"math/rand"
	"time"
)

/*
  获取gin上下文中的返回结构体地址

  参数:
    ctx:gin.Context的上下文

  作用:
   用于简化gin上下文中获取 ResponseBody响应体返回信息

  返回:
   查询并断言后的 ResponseBody响应体返回信息
*/
// ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
func ObtainResponseBody(ctx *gin.Context) *ResponseBody {
	body, _ := ctx.Get("ResponseBody")
	return body.(*ResponseBody)
}

/*
  获取并检测请求的内容

  参数:
    ctx:gin.Context的上下文
    body:当前的响应体的地址
    obj:需要获取并解析的结构体地址----切记是结构体的地址
    tool:工具类型，可以不传，不传则是默认全量非自定义错误信息格式验证，传入true则是进行自定义错误信息格式验证

  作用:
   用于简化获取并检查请求体内容的操作，且已经对错误信息进行了上下文响应体操作与错误打印，故使用时无特殊需求不需要再次重复操作

  返回:
   2.错误信息，如果没有则是nil
*/
// ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
func ObtainRequestContent(ctx *gin.Context, body *ResponseBody, obj interface{}) error {
	err := ctx.ShouldBindJSON(obj) //获取用户输入的内容

	//如果出现解析错误
	//----------------------------------------------------------------------------------------------------------
	if err != nil {
		//进行批量设置当前返回结构体
		body.BatchSettings(GetRequestContentErr, RequestBodyParameterParsingFailed, nil)

		return errors.New(RequestBodyParameterParsingFailed)
	}

	//验证传入的验证对象
	//----------------------------------------------------------------------------------------------------------
	var errs = ValidatorVerify(obj) // 错误信息

	if errs != nil {
		//进行批量设置当前返回结构体
		body.BatchSettings(Error, ParameterFormatError, nil)
		return errors.New(ParameterFormatError)
	}

	return nil
}

/*
  利用gin上下文的userInfo获取数据库中的用户信息

  参数:
    ctx:gin.Context的上下文
    body:当前的响应体的地址

  作用:
   用于简化查找获取用户信息的操作,且已经对错误信息进行了上下文响应体操作与错误打印，故使用时无特殊需求不需要再次重复操作

  返回:
   1.查询结果的用户信息结构体地址
   2.错误信息，如果没有则是nil
*/
// ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
func ObtainUserInfo(ctx *gin.Context, body *ResponseBody) (*UserInfo, error) {
	//获取上下文中的USerId
	//----------------------------------------------------------------------------------------------------------
	userId, ok := ctx.Get("userInfo")

	if !ok {
		body.BatchSettings(GetUserInfoErr, GetUserIdError, nil)
		return nil, errors.New(GetUserIdError)
	}

	//用户信息查询
	//----------------------------------------------------------------------------------------------------------
	var user = UserInfo{}
	//进行数据库查询
	err := user.OnceUser(userId.(*JwtToken).UserID)

	//如果查询失败则进行返回
	if err != nil {
		body.BatchSettings(GetUserInfoErr, GetUserMessageError, nil)
		return nil, errors.New(GetUserMessageError)
	}

	//返回最终结果
	return &user, nil
}

/*
  随机字符串生成函数

  参数:
    n:生成随机字符串的长度

  返回:
   1.随机生成后的字节串
   2.生成时的错误信息，若是没有错误则为nil

*/
// ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
func GenerateRandomBytes(n uint32) ([]byte, error) {
	b := make([]byte, n)
	_, err := crypto.Read(b)
	if err != nil {
		return nil, err
	}

	return b, nil
}

/*
  生成随机数字组成的字符串

  参数:
    length:生成随机字符串的长度

  返回:
   随机生成后的字符串
*/
// ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
func RandomNumber(length int) string {
	//进行重置随机种子
	time.Sleep(time.Microsecond)

	var (
		index  int                                                             // 承接随机的位数
		str    string                                                          // 最终组成的字符串
		digits = [...]string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"} // 原始数据数组
	)

	//进行循环获取当前数字
	//----------------------------------------------------------------------------------------------------------
	for i := 0; i < length; i++ {
		index = rand.Intn(10) // 随机出位数
		str += digits[index]  // 将随机出的位数index进行查询数据数组digits，然后进行字符串拼接
	}

	//返回生成的字符串
	return str
}
